#include "ringpuffer.h"
#include <string.h>
#include <stdio.h>

/**
* Erzeugt eines FIFO Ringpuffers
*@param targ leser Thread
*@param source schreiber thread
*@param buffersize groesse der Puffer 
*/
struct Rb_handle_t *initRb(int targ, int source, size_t buffersize)
{
	struct Rb_handle_t *ringpuffer;
	// malloc()
	ringpuffer=(struct Rb_handle_t *)malloc(sizeof(struct Rb_handle_t));
	//Ringpuffer:  Groesse des Ring = buffersize +1 
	ringpuffer->puffer=malloc((buffersize+1)*sizeof(char));
	//control: fuer die Makierung des Ende jeder Telegramm, gleiche gosse wie der Ringpuffer
	ringpuffer->control=(char *)malloc(buffersize+1);
	int i = 0;
	////Fuer sicherheit
	for( i = 0; i < buffersize+1; i++)
		ringpuffer->control[i] = 0;
	
	ringpuffer->targetThId = targ;
	ringpuffer->sourceThId = source;
	ringpuffer->freieplatz = buffersize;	// ganz leer
	ringpuffer->buffersize = buffersize;	// Ring

	// Am anfang rIdx = wIdx	
	ringpuffer->rIdx=0;
	ringpuffer->wIdx=0;

	return ringpuffer;  
}

/**
*	Element in den Puffer schreiben
*@param handle puffer
*@param targetThId lesende Thread
*@param sourceThId schreibende Thread
*@param *item Element zu schreiben
*@param itemsize groesse von item
*/
int writeRb(struct Rb_handle_t *handle, int targetThId, int sourceThId, const void *item, size_t itemsize)
{
	//Prueft ob Schreiben  moeglich ist:
	// Der Puffer definiert ist,
	// Die Threads sind die entsprechende Threads
	// Und es gibt genug platz um zu schreiben
	if(!handle || targetThId!= handle->targetThId || sourceThId!= handle->sourceThId || itemsize > handle->freieplatz)
		return -1;

	// Jeder byte kopieren
	int i = 0;
	// Write Index bewegen, bei Jeder Schreib
	for(; i < itemsize; i++, handle->wIdx = (handle->wIdx + 1)%(handle->buffersize +1))
	{
		((char*)(handle->puffer))[handle->wIdx] = ((char*)item)[i];
		handle->freieplatz--;
	}
	size_t ende_t = handle->wIdx == 0 ? handle->buffersize : handle->wIdx-1;
	handle->control[ende_t] = 1;  // Ende des Telegramm makieren
	return 1;
}


/**
* Element aus der Puffer lesen
*@param handle puffer
*@param targetThId lesende Thread
*@param sourceThId schreibende Thread
*@param *item Element zu schreiben
*@param itemsize groesse von item
*/
int readRb(struct Rb_handle_t *handle, int targetThId, int sourceThId, void *item, size_t *itemsize){

	//Prueft ob das Lesen  moeglich ist:
	// Der Puffer definiert ist,
	// Die Threads sind die entsprechende Threads
	if(!handle || targetThId!= handle->targetThId || sourceThId!= handle->sourceThId )
		return -2;

	// Falls lesen moeglich ist, aber das Puffer ist leer
	if(handle->rIdx==handle->wIdx)
	{
		*itemsize = 0;
		return 0;	// Puffer leer
	}
	
	// Man musst nichts auslesen
	if(*itemsize <= 0)
		return 1;

	int i = 0;
	int index = 0;
	// Jeder byte aus der aktuell Telegramm in Item kopieren
	// bis item voll ist oder bis das gesamt Telegramm kopiert wuerde
	do
	{
		index = handle->rIdx;	//  index des Aktuelles Byte zu lesen
		((char*)item)[i] = ((char*)(handle->puffer))[index];  // Byte auslesen
		handle->rIdx = (handle->rIdx + 1)%(handle->buffersize +1);// rIdx zu naechste Byte bewegen
		handle->freieplatz++;//Anzahl der freieplaetz aktualisieren
		i++;
	}
	while(i< *itemsize && handle->control[index]!=1); // Solange noch nicht fertig
	
	*itemsize = i;		// i ist die anzahl der gelesen Bytes
	
	// wenn das Ende des Telegramm nicht ereicht wuerde
	if(handle->control[index] != 1)
		return -1;
	// gelesen Telegramm aus dem Puffer loeschen	
	handle->control[index] = 0;
	return 1;
}



/**
*	Ringpuffer loeschen
*@param handle object zu loeschen
*/
int freeRb(struct Rb_handle_t *handle)
{
	//Wenn definiert
	if(handle)
	{
		// Puffer loeschen
		if(handle->puffer)
		{
			free(handle->puffer);
			handle->puffer = 0;
		}
		
		// ControlArray loeschen
		if(handle->control)
		{
			free(handle->control);
			handle->control = 0;
		}
		free(handle);
		handle = 0;
		return 0; // Loeschen erfolgreich
	}
	return -1; // War warscheinlich schon geloescht
}
